package org.example.util;

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.example.annotations.HttpMethod;
import org.example.annotations.QueryParam;
import org.example.annotations.RequestBody;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * @author wxm
 * @date 2025/2/26 9:13
 */
public class HttpServiceProxy implements InvocationHandler {
    // private final HttpClient client = HttpClient.newHttpClient();
    OkHttpClient client = new OkHttpClient();
    // 使用ConcurrentHashMap来缓存已经创建的代理实例
    private static final ConcurrentHashMap<Class<?>, Object> proxyCache = new ConcurrentHashMap<>();

    /**
     * 创建一个指定类型的代理实例。
     *
     * @param service 服务接口类
     * @param <T>     服务接口类型
     * @return 返回创建的代理实例
     * @throws IllegalArgumentException 如果传入的参数无效
     */
    public static <T> T create(Class<T> service) {
        try {
            // 尝试从缓存中获取已有的代理实例
            @SuppressWarnings("unchecked")
            T cachedProxy = (T) proxyCache.get(service);
            if (cachedProxy != null) {
                return cachedProxy;
            }
            // 创建新的代理实例
            T newProxy = (T) Proxy.newProxyInstance(service.getClassLoader(),
                    new Class<?>[]{service},
                    new HttpServiceProxy()
            );

            // 将新创建的代理实例放入缓存
            proxyCache.putIfAbsent(service, newProxy);
            return newProxy;
        } catch (IllegalArgumentException | ClassCastException e) {
            throw new IllegalArgumentException("Failed to create proxy for service: " + service.getName(), e);
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        HttpMethod httpRequest = method.getAnnotation(HttpMethod.class);
        if (httpRequest == null) {
            throw new RuntimeException("Method not annotated with @HttpRequest");
        }

        // 构建请求参数
        Map<String, Object> queryParams = new HashMap<>();
        Object requestBody = null;

        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].isAnnotationPresent(QueryParam.class)) {
                QueryParam annotation = parameters[i].getAnnotation(QueryParam.class);
                queryParams.put(annotation.value(), args[i]);
            } else if (parameters[i].isAnnotationPresent(RequestBody.class)) {
                requestBody = args[i];
            }
        }

        // 构建 URL
        String url = buildUrl(httpRequest.url(), queryParams);
        // 创建请求体
        okhttp3.RequestBody okHttpBody = requestBody != null ?
                okhttp3.RequestBody.create(JSONObject.toJSONString(requestBody), MediaType.get(httpRequest.contentType())) :
                null;

        // 创建请求
        Request.Builder requestBuilder = new Request.Builder()
                .url(url);

        // 使用 Map 来简化 HTTP 方法的选择逻辑
        Map<String, Function<okhttp3.RequestBody, Request.Builder>> httpMethods = Map.of(
                "GET", body -> requestBuilder.get(),
                "POST", requestBuilder::post,
                "PUT", requestBuilder::put,
                "DELETE", requestBuilder::delete
        );
        String httpMethod = httpRequest.method().toUpperCase();
        if (!httpMethods.containsKey(httpMethod)) {
            throw new IllegalArgumentException("Unsupported HTTP method: " + httpRequest.method());
        }

        Request request = okHttpBody == null ? httpMethods.get(httpMethod).apply(new FormBody.Builder().build()).build()
                : httpMethods.get(httpMethod).apply(okHttpBody).build();

        // 发送请求
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new RuntimeException("Unexpected code " + response);
            }
            // 返回结果（简单处理，实际需要根据返回类型转换）
            return response.body().string();
        }
    }

    private String buildUrl(String baseUrl, Map<String, Object> params) {
        if (params.isEmpty()) return baseUrl;

        StringBuilder sb = new StringBuilder(baseUrl);
        sb.append("?");
        params.forEach((k, v) -> sb.append(k).append("=").append(v).append("&"));
        return sb.deleteCharAt(sb.length() - 1).toString();
    }
}
